package com.cocotingo.snail.template.previewer;

import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.RenderingHints;
import java.awt.geom.Rectangle2D;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import com.cocotingo.snail.MouseEvent;
import com.cocotingo.snail.PaintMode;
import com.cocotingo.snail.ViewGraphics;
import com.cocotingo.snail.template.EventHandler;
import com.cocotingo.snail.template.TemplateView;
import com.cocotingo.snail.text.TextView;
import com.cocotingo.snail.util.Alignment;

public final class TemplatePreviewerView extends TemplateView implements EventHandler {
	
	private static final Font debugFont = new Font(Font.MONOSPACED, Font.PLAIN, 10);
	public static final String SelectedViewChanged = "selectedViewChanged";
	
	private final TemplatePreviewerView rootPreviewerView;
	private String id; // can be null
	private String typeName; // not null
	private final Map<String, String> handlerBindings;
	private final Map<String, String> attributes;
	
	private boolean mouseOn;
	private TemplatePreviewerView selecteView;
	private final TextView title;
	
	public TemplatePreviewerView(TemplatePreviewerView root) {
		this.rootPreviewerView = root;
		
		title = new TextView();
		title.setTextAlignment(Alignment.LEFT_CENTER);
		title.setBackgroundColor(Color.magenta);
		title.setTextColor(Color.white);
		title.setAntialiased(false);
		title.setFont(debugFont);
		title.setPosition(1, 1);
		title.setHidden(true);
		addSubview(title);
		
		selecteView = null;
		setTypeName(null);
		handlerBindings = new HashMap<String, String>();
		attributes = new HashMap<String, String>();
		addEventHandler(TemplateView.REPAINT, this);
		addEventHandler(TemplateView.MOUSE_ENTERED, this);
		addEventHandler(TemplateView.MOUSE_EXITED, this);
		addEventHandler(TemplateView.SIZE_CHANGED, this);
		addEventHandler(TemplateView.POSITION_CHANGED, this);
		addEventHandler(TemplateView.POST_MOUSE_PRESSED, this);
		setBackgroundColor(Color.white);
		setPaintMode(PaintMode.DIRECTLY);
		mouseOn = false;
	}
	
	@Override
	public void handle(TemplateView sender, String eventName, Object arg) {
		if (eventName.equals(TemplateView.REPAINT)) {
			ViewGraphics g = (ViewGraphics) arg;
			draw(g);
		} else if (eventName.equals(TemplateView.MOUSE_ENTERED)) {
			mouseOn = true;
			title.setHidden(false);
			updateTitle();
			setNeedsRepaint();
		} else if (eventName.equals(TemplateView.MOUSE_EXITED)) {
			mouseOn = false;
			title.setHidden(true);
			setNeedsRepaint();
		} else if (eventName.equals(TemplateView.SIZE_CHANGED)) {
			updateTitle();
		} else if (eventName.equals(TemplateView.POSITION_CHANGED)) {
			updateTitle();
		} else if (eventName.equals(TemplateView.POST_MOUSE_PRESSED)) {
			MouseEvent e = (MouseEvent) arg;
			select();
			e.handle();
		}
	}
	
	private void changeSelection(TemplatePreviewerView view) {
		if (view == selecteView) return;
		
		if (selecteView != null) {
			selecteView.deselected();
		}
		selecteView = view;
		if (selecteView != null) {
			selecteView.selected();
		}
		fireEvent(SelectedViewChanged, selecteView);
	}
	
	public void select() {
		if (getRootPreviewerView() != null) {
			getRootPreviewerView().changeSelection(this);
		} else {
			changeSelection(this);
		}
	}
	
	private void selected() {
		setBackgroundColor(new Color(230, 230, 230));
	}
	
	private void deselected() {
		setBackgroundColor(Color.white);
	}
	
	public TemplatePreviewerView getSelecteView() {
		return selecteView;
	}
	
	private void draw(ViewGraphics g) {
		if (mouseOn) {
			g.setColor(Color.magenta);
		} else {
			g.setColor(Color.orange);
		}
		g.setFont(debugFont);
		g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
		
		// border
		g.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
		
		// show label
		String label = id == null ? typeName : String.format("%s : %s", id, typeName);
		
		FontMetrics fm = g.getFontMetrics();
		int ascent = fm.getMaxAscent();
		Rectangle2D rect = fm.getStringBounds(label, g);
		g.fillRect(0, 0, (int) rect.getWidth() + 1, (int) rect.getHeight() + 1);
		g.setColor(Color.black);
		g.drawString(label, 1, ascent + 1);
		
	}
	
	private void updateTitle() {
		if (!title.isHidden()) {
			String label = id == null ? typeName : String.format("%s : %s", id, typeName);
			label = String.format("%s (%d,%d,%d,%d)", label, getLeft(), getTop(), getWidth(), getHeight());
			title.setText(label);
			title.setSize(title.getPreferredSize());
		}
	}
	
	public String getID() {
		return id;
	}
	
	public void setID(String id) {
		this.id = id;
		updateTitle();
	}
	
	public String getTypeName() {
		return typeName;
	}
	
	public void setTypeName(String typeName) {
		if (typeName == null) typeName = "View";
		this.typeName = typeName;
		updateTitle();
	}
	
	public void addHandlerBinding(String event, String handler) {
		handlerBindings.put(event, handler);
	}
	
	public Set<Map.Entry<String, String>> getAllHandlerBindings() {
		return handlerBindings.entrySet();
	}
	
	public void addAttribute(String name, String value) {
		attributes.put(name, value);
	}
	
	public Set<Map.Entry<String, String>> getAllAttributes() {
		return attributes.entrySet();
	}
	
	public TemplatePreviewerView getRootPreviewerView() {
		return rootPreviewerView;
	}

}
